use std::path::PathBuf;

use anyhow::{Result as AnyResult, anyhow};
use axum::{
    Router,
    extract::{Path, Query, State},
    routing::get,
};
use axum_ifnk_common::{
    app_error,
    prelude::{AppError, Response},
};
use serde::Deserialize;
use serde::Serialize;
use utoipa::ToSchema;

use crate::AppState;
use crate::domain::{FileTimeScope, NodeConf, Project};
use crate::services::{JsonDataService, NodeConfService, TimeScopeService};

pub fn routes() -> Router<AppState> {
    Router::new()
        .route("/station-audio/projects/{id}", get(get_project_by_id))
        .route("/station-audio/stations", get(get_station_infos))
}

#[utoipa::path(
    get,
    path = "/station-audio/projects/{id}",
    params(("id" = i32, Path, description = "项目ID")),
    responses((status = 200, description = "项目详情", body = Response<Project>)),
    tag = "声波历史"
)]
async fn get_project_by_id(
    State(state): State<AppState>,
    Path(project_id): Path<i32>,
) -> Result<Response<Project>, AppError> {
    let project = state
        .json_data_service
        .get_project_by_id(project_id)
        .map_err(|err| app_error!(500, "读取项目信息失败: {}", err))?;

    match project {
        Some(project) => Ok(Response::success(project)),
        None => Err(app_error!(404, "项目 {} 不存在", project_id)),
    }
}

#[derive(Debug, Deserialize, ToSchema)]
pub struct StationQuery {
    #[serde(default)]
    project_id: Option<i32>,
    #[serde(default)]
    folder: Option<String>,
    #[serde(default)]
    wave_type: Option<String>,
}

#[derive(Debug, Serialize, ToSchema)]
pub struct StationInfoResponse {
    boardid: i32,
    alias: String,
    ipaddr: String,
    smprate: i32,
    channels: i32,
    wave_type: String,
    folder_path: String,
    time_scopes: Vec<FileTimeScope>,
}

#[utoipa::path(
    get,
    path = "/station-audio/stations",
    params(
        ("project_id" = Option<i32>, Query, description = "项目ID"),
        ("folder" = Option<String>, Query, description = "项目数据文件夹"),
        ("wave_type" = Option<String>, Query, description = "波形类型过滤")
    ),
    responses(
        (status = 200, description = "测站信息列表", body = Response<Vec<StationInfoResponse>>)
    ),
    tag = "声波历史"
)]
async fn get_station_infos(
    State(state): State<AppState>,
    Query(query): Query<StationQuery>,
) -> Result<Response<Vec<StationInfoResponse>>, AppError> {
    let folder_path = determine_folder(&state.json_data_service, &query)
        .map_err(|err| app_error!(500, "获取项目文件夹失败: {}", err))?;

    let nodes = NodeConfService::read_nodes_config(&folder_path)
        .map_err(|err| app_error!(500, "读取 nodesconf.json 失败: {}", err))?;

    if nodes.is_empty() {
        return Ok(Response::success(Vec::new()));
    }

    let filtered: Vec<NodeConf> = if let Some(ref wave_type) = query.wave_type {
        nodes
            .into_iter()
            .filter(|node| node.wave_type == *wave_type)
            .collect()
    } else {
        nodes
    };

    let mut results = Vec::with_capacity(filtered.len());
    for node in filtered {
        let folder_name = NodeConfService::get_station_folder_name(&folder_path, &node);
        let station_folder = PathBuf::from(&folder_path).join(&folder_name);

        let time_scopes = TimeScopeService::collect_acoustic_file_scopes(
            &station_folder,
            node.smprate as usize,
            node.channels as usize,
            node.depth(),
            0.0,
        )
        .map_err(|err| app_error!(500, "解析声波文件失败({}): {}", folder_name, err))?;

        let response = StationInfoResponse {
            boardid: node.boardid,
            alias: node.alias.clone(),
            ipaddr: node.ipaddr.clone().unwrap_or_default(),
            smprate: node.smprate,
            channels: node.channels,
            wave_type: node.wave_type.clone(),
            folder_path: station_folder.to_string_lossy().to_string(),
            time_scopes,
        };
        results.push(response);
    }

    Ok(Response::success(results))
}

fn determine_folder(json_service: &JsonDataService, query: &StationQuery) -> AnyResult<PathBuf> {
    if let Some(folder) = &query.folder {
        return Ok(PathBuf::from(folder));
    }

    let project_id = query
        .project_id
        .ok_or_else(|| anyhow!("必须提供 project_id 或 folder 参数"))?;

    let project = json_service
        .get_project_by_id(project_id)?
        .ok_or_else(|| anyhow!("项目 {} 不存在", project_id))?;

    Ok(PathBuf::from(project.data_directory).join(project.project_name))
}
